import {
  AudioFilled,
  AudioOutlined,
  CustomerServiceOutlined,
  PhoneOutlined,
  VerticalAlignBottomOutlined,
} from '@ant-design/icons';
import { Button, Empty, message } from 'antd';
import Tooltip from 'antd/es/tooltip';
import { WAudio } from 'components/UILibrary/wAudio';
import moment from 'moment';
import React from 'react';
import { downloadCallRecord, getDialogue, interceptCall } from 'admin/servers/servers';
import { getSysSip } from 'servers/sip';
import store from 'store';
import './style.scss';
import { JSONObject } from '../../admin/schema/common';
import { getStateDom } from 'admin/pages/Task/components/TaskTool';
import { filterDialogue, webDebug } from 'utils/tools';
import { tasksHangup } from 'seats/servers/servers';
import { connect } from 'react-redux';
import { setInterceptCallId } from 'store/root/action';
import { checkPermission } from 'permission/Index';

export interface ChatMessage {
  /**序号*/
  index: number;
  /**
   * 消息来源
   * caller-我方（左侧）
   * called-对方（右侧）
   */
  role: 'caller' | 'called' | 'man';
  /**
   * 消息
   */
  message: string;
  /**
   * 消息语言地址
   */
  sound: string;
  /**
   * 未理解：0：未理解，1：正常
   */
  status: number;
  /**方便测试，交易流水号 */
  callRecordId?: string;
}

export interface ChatProp {
  /**
   * 记录消息
   */
  messages?: ChatMessage[];
  /**
   * 是否展示通话记录header，默认为true
   */
  showStatusHeader?: boolean;
  /**
   * 是否在头部展示全部录音播放，默认为false
   */
  showHeadBar?: boolean;
  /**
   * 是否提供音频下载，默认为false
   */
  showDownload?: boolean;
  /**
   *  头部录音的url
   */
  talkRecord?: string;
  /**
   * 通话号码（showStatusHeader为true时必填）
   */
  phoneNum?: string;
  /**
   * 呼叫状态（showStatusHeader为true时必填）
   */
  /** 号码状态，0-未呼，1-呼叫中，2-等待坐席，3-通话中 */
  status?: number;
  /**
   * 回话id
   */
  callRecordId?: string;
  /**
   * 呼叫中心id
   */
  centerCallId?: string;
  /**
   * call串行id
   */
  callSerialNumber?: string;
  /**
   * 是否展示“查看历史”
   */
  showHistoryLink?: boolean;
  /**
   * 类型：为空，默认是【任务外呼】通话记录；'record'，【流程调试】通话记录
   */
  chatType?: string;
  /**
   * 获得历史记录后的回调
   */
  onGetHistory?: (msg: ChatMessage[], callRecordId: string, callSerialNumber: string) => any;
}

export interface ChatState extends ChatProp {
  /**通话中 */
  inCall: boolean;
  /**
   * 当前播放中，图标提示
   */
  playings: Array<boolean>;
}
/**管理端-chat组件：运用场景：机器人任务详情->人工监听（通话记录实时显示），任务详情->通话记录显示，流程调试-通话记录显示 */
class ChatBase extends React.Component<ChatProp, ChatState> {
  /**
   * 接收方头像
   */
  private calledImg: string;

  /**
   * 发送方头像
   */
  private callerImg: string;
  /**
   * 当前页面播放对象
   */
  private musicAudio: HTMLAudioElement;

  /**
   * 会话内容容器
   */
  private bodyRef: React.RefObject<HTMLDivElement>;
  /**
   * 音频播放容器
   */
  private audioRef: React.RefObject<any>;

  constructor(prop: ChatProp) {
    super(prop);
    this.musicAudio = new Audio();
    this.calledImg = '/webapp/clientAva.jpeg';
    this.callerImg = '/webapp/logo192.png';
    this.bodyRef = React.createRef();
    this.audioRef = React.createRef();
    this.state = {
      chatType: prop.chatType || '',
      showHistoryLink: !!prop.showHistoryLink,
      callRecordId: prop.callRecordId,
      messages: prop.messages || [],
      showDownload: prop.showDownload == null ? false : prop.showDownload,
      showStatusHeader: prop.showStatusHeader == null ? true : prop.showStatusHeader,
      callSerialNumber: prop.callSerialNumber || '',
      talkRecord: prop.talkRecord,
      centerCallId: prop.centerCallId || '',
      showHeadBar: !!prop.showHeadBar,
      phoneNum: void 0,
      status: prop.status,
      inCall: false,
      playings: [],
    };

    this.handleInterceptCall = this.handleInterceptCall.bind(this);
    this.handleStopCall = this.handleStopCall.bind(this);
    this.fetchHistory = this.fetchHistory.bind(this);
    this.playSound = this.playSound.bind(this);
  }

  /**
   * 设置会话记录
   */
  public setRecord(message: ChatMessage[]): void {
    this.setState(
      {
        messages: message,
      },
      () => {
        this.scrollToBottom();
      }
    );
  }

  /**
   * 得到当前会话的通话号码
   */
  public getPhone(): string {
    return this.state.phoneNum || '';
  }

  /**
   * 得到当前会话的Id
   */
  public getCallRecordId(): string {
    return this.state.callRecordId || '';
  }

  /**
   * 播放音频-单句
   */
  private playSound(item: ChatMessage, index: number): void {
    // 顶部播放暂停
    this.audioRef.current && this.audioRef.current.pauseAudio();
    // 其他单句暂停
    this.musicAudio.pause();
    console.log(item, '播放音频');
    const arr = [];
    arr[index] = true;
    this.setState({
      playings: arr,
    });
    // 单句-切换播放
    this.musicAudio.src = (process.env.REACT_APP_API_URL || '') + item.sound;
    this.musicAudio.play().catch((error: any) => {
      // 当播放异常时，走异常流程
      console.log('播放异常：', error);
      this.setState({
        playings: [],
      });
    });

    this.musicAudio.onpause = () => {
      console.log('单句-播放暂停');
      this.setState({
        playings: [],
      });
    };
    this.musicAudio.onended = () => {
      console.log('单句-播放结束');
      // 播放完，恢复为初始状态
      this.setState({
        playings: [],
      });
    };
  }

  componentDidMount() {}

  /**
   * 频繁比较state和prop是一件比较麻烦的事（由于地址引用，需要转字符串再比较），
   * 考虑到开销将message的更新提取为setRecord方法
   */
  componentDidUpdate(prop: ChatProp): void {
    const state = this.state;
    const checkPhone = state.phoneNum === prop.phoneNum;
    const checkStatus = state.status === prop.status;
    const checkCallId = state.callRecordId === prop.callRecordId;
    const checkCenterId = state.centerCallId === prop.centerCallId;
    const checkTalkRecord = state.talkRecord === prop.talkRecord;
    if (checkPhone && checkStatus && checkCallId && checkCenterId && checkTalkRecord) {
      return;
    }
    this.setState(
      {
        phoneNum: prop.phoneNum,
        status: prop.status,
        callRecordId: prop.callRecordId,
        centerCallId: prop.centerCallId,
        talkRecord: prop.talkRecord,
      },
      () => {
        this.forceUpdate();
      }
    );
  }
  componentWillUnmount() {
    const { centerCallId } = this.state;
    console.log('【chat组件】*****unmount*****', centerCallId);
    // 查询截听id，如果是当前弹屏，需要将缓存置空
    const interceptCallId = (this.props as JSONObject).interceptCallId;
    if (centerCallId && centerCallId === interceptCallId) {
      console.log('清除====监听通话:', centerCallId);
      (this.props as JSONObject).setInterceptCallId('');
    }
    // 单句播放暂停
    this.musicAudio.pause();
    this.setState = (state, callback) => {
      return;
    };
  }

  /**
   * 置空会话
   */
  public clear(): void {
    this.setState({
      messages: [],
      phoneNum: void 0,
    });
  }
  /**
   * 管理端-任务详情-监听通话-开启
   */
  private async handleInterceptCall(): Promise<void> {
    if ((this.props as JSONObject).seatState !== 2) {
      message.warning('抱歉，请先签入');
      return;
    }
    const { centerCallId } = this.state;
    const seatNum = (store.getState() as JSONObject).userInfo?.seatsNumber;
    if (!centerCallId || !seatNum) {
      console.log('监听通话-异常:callId和坐席工号不能为空', centerCallId, seatNum);
      return;
    }
    // 从截听数组，查找正在被截听的通话，判断
    const interceptCallId = (this.props as JSONObject).interceptCallId;
    if (interceptCallId) {
      // 情况1-存在，给出提示
      message.warning('请先关闭当前截听，再进行新的截听');
      return;
    }
    // 情况1-不存在，直接开启B
    // 更新截听数组
    try {
      await interceptCall(centerCallId as string, {
        intercepter: seatNum,
      });
      console.log('监听通话-begin', centerCallId, seatNum);
      (this.props as JSONObject).setInterceptCallId(centerCallId);
      this.setState({
        inCall: true,
      });
    } catch (error) {
      console.error(`系统异常: ${JSON.stringify(error)}`);
    }
  }
  /**
   * 管理端-任务详情-监听通话-关闭
   */
  public async handleStopCall(): Promise<void> {
    const { centerCallId } = this.state;
    if (!centerCallId) return;
    console.log('请求接口：关闭====监听通话:', centerCallId);
    try {
      await tasksHangup(centerCallId);
      this.setState(
        {
          inCall: false,
        },
        () => {
          // FS挂断截听
          getSysSip()
            .waitInit()
            .then(ins => {
              ins.stopAudio();
              // ins.hangup();
            });
        }
      );
      const interceptCallId = (this.props as JSONObject).interceptCallId;
      if (centerCallId === interceptCallId) {
        console.log('清除====监听通话:', centerCallId);
        (this.props as JSONObject).setInterceptCallId('');
      }
    } catch (error) {
      console.error(`系统异常: ${JSON.stringify(error)}`);
    }
  }

  /**
   * 查询历史
   */
  private fetchHistory() {
    getDialogue(
      {
        callRecordId: this.state.callRecordId as string,
        time: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'),
      },
      this.state.chatType
    )
      .then(res => {
        // 点击查看历史记录时，页面接收到的所有推送消息
        const record = this.state.messages;
        // 完整通话记录：历史记录拼接在推送消息前面
        const msg = res.data
          .map(item => {
            return {
              index: item.index,
              role: item.role === 1 ? 'caller' : 'called',
              message: item.text,
              sound: item.url,
              status: item.status,
            };
          })
          .concat(record as ChatMessage[]);
        // 通话记录拼接后去重
        const newMsg = filterDialogue(msg as ChatMessage[]);
        // 回调
        this.props.onGetHistory &&
          this.props.onGetHistory(
            newMsg,
            this.state.callRecordId as string,
            this.state.callSerialNumber as string
          );
        this.setState({
          showHistoryLink: false,
          messages: newMsg as ChatMessage[],
        });
      })
      .catch(error => {
        console.error(`系统异常: ${JSON.stringify(error)}`);
      });
  }

  /**
   * 滚动到最底部
   */
  public scrollToBottom(): void {
    const domContainer = this.bodyRef.current;
    if (!domContainer) {
      return;
    }
    const scrollDistance = domContainer.clientHeight + domContainer.scrollTop;
    const scrollHeight = domContainer.scrollHeight;
    if (scrollDistance > scrollHeight - 20 || scrollDistance < scrollHeight + 20) {
      domContainer.scroll(0, 200000);
    }
  }

  /**下载录音文件 */
  private downloadRecord = async () => {
    const { callRecordId, talkRecord } = this.state;
    console.log('请求下载录音接口-流水号', callRecordId, talkRecord);
    if (!callRecordId || !talkRecord) {
      return;
    }
    try {
      const arr = talkRecord.split('/');
      const fileName = arr[arr.length - 1];
      const data: any = await downloadCallRecord(callRecordId);
      console.log(data, '下载');
      if (!data) {
        message.warning('文件下载失败');
        return;
      }
      const link = document.createElement('a');
      link.style.display = 'none';
      link.href = talkRecord + '?n=aaa';
      link.setAttribute('download', fileName);
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link); // 下载完成移除元素
    } catch (error) {
      console.error(`系统异常: ${JSON.stringify(error)}`);
    }
  };

  render() {
    const {
      showHeadBar,
      showStatusHeader,
      phoneNum,
      messages,
      status,
      inCall,
      showHistoryLink,
      talkRecord,
      centerCallId,
      callRecordId,
    } = this.state;
    const { calledImg, callerImg, bodyRef, audioRef, musicAudio } = this;
    const playIconStyle = {
      marginRight: '5px',
      fontSize: '16px',
    };
    const playingIconStyle = {
      marginRight: '5px',
      fontSize: '16px',
    };
    // 转人工样式
    const statusIconStyle = {
      fontSize: '20px',
      transform: 'translateY(5px)',
      color: '#1890ff',
    };
    // 呼叫中，响铃样式
    const placeholderIconStyle = {
      fontSize: '75px',
      color: 'red',
    };
    // 挂机样式
    const stopCallStyle = {
      color: 'white',
      backgroundColor: 'red',
      padding: '5px',
      borderRadius: '50%',
      transform: 'rotate(-135deg)',
      fontSize: '20px',
    };

    return (
      <>
        {showStatusHeader && (
          <div className="chat-status-header">
            <span className="chat-statusheader-phone">
              {webDebug && <b className="debug-style">【{callRecordId}】</b>}
              {phoneNum}
            </span>
            <span className="chat-statusheader-status">{getStateDom(status as number)}</span>
            {/* status：3-通话中 */}
            {(status === 2 || status === 3) && checkPermission('/seats/callTask') && (
              <span className="chat-statusheader-statusicon">
                {/* 场景：机器人任务，任务详情，正在通话的聊天窗口，右上角可操作监听 */}
                {inCall ? (
                  <PhoneOutlined
                    key={'phone_' + callRecordId}
                    style={stopCallStyle}
                    onClick={this.handleStopCall}
                  />
                ) : (
                  <Tooltip placement="bottomRight" title="切换人工前请确保网络和耳麦连接正常">
                    <CustomerServiceOutlined
                      key={'listen_' + callRecordId}
                      style={statusIconStyle}
                      onClick={this.handleInterceptCall}
                    />
                  </Tooltip>
                )}
              </span>
            )}
            <span className="chat-statusheader-talktime"></span>
            {webDebug && <b className="debug-style">【{centerCallId}】</b>}
          </div>
        )}
        <div className="chat-sound-header">
          {showHeadBar && talkRecord && talkRecord?.indexOf('null') < 0 && (
            <>
              <div className="chat-sound-bar">
                <WAudio
                  ref={audioRef}
                  id={talkRecord}
                  src={talkRecord as string}
                  outAudio={musicAudio}
                />
              </div>
              <Button
                type="link"
                icon={<VerticalAlignBottomOutlined />}
                // href={talkRecord + '?n=aaa'}
                // n=aaa为后端定义传参，方便识别为下载文件
                onClick={this.downloadRecord}
                // download
              />
            </>
          )}
        </div>
        <div className="chat-body" ref={bodyRef}>
          {/* status：3-通话中-查看历史 */}
          {showHistoryLink && (status === 2 || status === 3) && (
            <div className="chat-showhistory">
              <Button type="link" onClick={this.fetchHistory}>
                查看历史
              </Button>
            </div>
          )}
          {/* 历史记录-信息展示 */}
          {messages?.length !== 0 &&
            messages?.map((item, index) => {
              if (item.role === 'caller') {
                return (
                  <div className="chat-message" key={'caller_' + index}>
                    <span className="chat-message-caller">
                      <img className="chat-ava" src={callerImg} alt="caller" />
                    </span>
                    <span className="chat-message-callermessage">
                      {webDebug && (
                        <>
                          <b className="debug-style">【{callRecordId}】</b>
                          【序号{item.index}】
                        </>
                      )}
                      {item.message}
                    </span>
                  </div>
                );
              } else if (item.role === 'called') {
                return (
                  <div
                    className={
                      item.status
                        ? 'chat-message called-message'
                        : 'chat-message called-message chat-message-not-understand'
                    }
                    key={'called_' + index}
                  >
                    <span className="chat-message-calledava">
                      <img className="chat-ava" src={calledImg} alt="called" />
                    </span>
                    <span className="chat-message-calledmessage">
                      <>
                        {!!item.sound && (
                          <>
                            {this.state.playings[index] ? (
                              <AudioOutlined style={playingIconStyle} />
                            ) : (
                              <AudioFilled
                                style={playIconStyle}
                                onClick={() => this.playSound(item, index)}
                              />
                            )}
                          </>
                        )}
                        {webDebug && (
                          <>
                            <b className="debug-style">【{callRecordId}】</b>
                            【序号{item.index}】
                          </>
                        )}
                        {item.message}
                      </>
                    </span>
                    {item.status === 0 && <span className="messaget-tip">未理解</span>}
                  </div>
                );
              } else {
                return (
                  <div key={'called_' + index} className="chat-transferman">
                    {webDebug && (
                      <>
                        <b className="debug-style">【{callRecordId}】</b>
                        【序号{item.index}】
                      </>
                    )}
                    {item.message}
                  </div>
                );
              }
            })}
          {messages?.length === 0 && status !== 1 && (
            <Empty description={<span>无记录</span>}></Empty>
          )}
          {/* status-呼叫中，响铃 */}
          {status === 1 && (
            <div className="chat-incall-placeholder">
              <PhoneOutlined style={placeholderIconStyle} />
            </div>
          )}
        </div>
      </>
    );
  }
}

// state 注入props
const mapStateToProps = (state: JSONObject) => {
  return {
    interceptCallId: state.interceptCallId,
    seatState: state.checkInState,
  };
};
// action 注入props
const mapDispatchToProps = {
  setInterceptCallId,
};

export const Chat = connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true })(
  ChatBase
);

/**
 * 测试用例
 */
export const ChatCollectTest: React.FC = () => {
  const initValue = [
    {
      role: 'caller',
      message: '试试运用自如！',
    },
    {
      role: 'called',
      message: 'wow awsome!',
    },
    {
      role: 'man',
      message: '2020/12/01 转人工至aa',
    },
  ] as ChatMessage[];

  return (
    <>
      <Chat key="test" messages={initValue} showStatusHeader={true} />
    </>
  );
};
